

let THREE=require('three');
import SeparationAxisFixed from "../../compute/separation-axis-fixed";

const EPSILON=1e-12;
const AXIS_Z=new  THREE.Vector3(0,0,1);
let _v={
    vec0:new THREE.Vector3(),
    vec1:new THREE.Vector3(),
    vec2:new THREE.Vector3(),
    vec3:new THREE.Vector3(),
    vec4:new THREE.Vector3(),
    vec5:new THREE.Vector3(),
    vec6:new THREE.Vector3(),
    vec7:new THREE.Vector3(),
    vec00:new THREE.Vector3(),
    vec01:new THREE.Vector3(),
    vec02:new THREE.Vector3(),
    vec03:new THREE.Vector3(),
    vec04:new THREE.Vector3(),
    vec05:new THREE.Vector3(),
    vec06:new THREE.Vector3(),
    vec07:new THREE.Vector3(),
    vec08:new THREE.Vector3(),
    vec09:new THREE.Vector3(),
    vec10:new THREE.Vector3(),
    vec11:new THREE.Vector3(),
    vec12:new THREE.Vector3(),
    vec13:new THREE.Vector3(),
    vec14:new THREE.Vector3(),
    vec15:new THREE.Vector3(),
    vec16:new THREE.Vector3(),
    mat0:new THREE.Matrix4(),
};

/**
 * 图元计算
 */
let PrimitiveCompute={
    /**
     * 是否相等（1e-6范围）
     * @param x1
     * @param x2
     * @returns {boolean}
     */
    isEqual:(x1,x2)=>{
        let delta=1e-6;
        return Math.abs(x2-x1)<delta;
    },
    /**
     * 点到平面的距离（平方）
     * @param point
     * @param normal
     * @param pPoint
     * @returns {*}
     */
    pointDistanceToPlane:(point,normal,pPoint)=>{
        let d=pPoint.dot(normal);
        return normal.dot(point)+d;
    },
    /**
     * 点到线段的距离（平方）
     * @param point
     * @param start
     * @param end
     * @param pointOnLine
     * @returns {number}
     */
    pointDistanceToSeg:(point,start,end,pointOnLine)=>{
        let ls=_v.vec0.copy(start);
        let le=_v.vec1.copy(end);
        let dir=_v.vec2.subVectors(le,ls).normalize();
        let q=_v.vec3.copy(point);

        let t=dir.dot(_v.vec4.subVectors(q,ls));
        let dv=_v.vec6;
        if(t<0){
            dv.subVectors(q,ls);
            pointOnLine.copy(ls);
        }else if(t>1){
            dv.subVectors(q,le);
            pointOnLine.copy(le);
        }else{
            let qp=_v.vec5.addVectors(ls,dir.multiplyScalar(t));
            dv.subVectors(q,qp);
            pointOnLine.copy(qp);
        }
        return dv.dot(dv);
    },
    /**
     * 点到包围盒的距离（平方）
     * @param point
     * @param extents
     * @returns {number}
     */
    pointDistanceToAabb:(point,extents)=>{
        _v.vec0.set(-extents[0],-extents[1],-extents[2]);
        _v.vec1.set(extents[0],extents[1],extents[2]);
        let cp=_v.vec2.copy(point).clamp(_v.vec0,_v.vec1);
        return cp.distanceToSquared(point);
    },
    /**
     * 线段与线段之间的距离（平方）
     * @param start0
     * @param end0
     * @param start1
     * @param end1
     * @param pointOnA
     * @param pointOnB
     * @returns {number}
     */
    segmentDistanceToSegment:(start0,end0,start1,end1,pointOnA,pointOnB)=>{
        let base0=_v.vec0.copy(start0);
        let base1=_v.vec1.copy(start1);
        let dir0=_v.vec2.subVectors(end0,start0);
        let dir1=_v.vec3.subVectors(end1,start1);
        let u=_v.vec4.subVectors(base0,base1);
        let a=dir0.dot(dir0);
        let b=dir0.dot(dir1);
        let c=dir1.dot(dir1);
        let d=dir0.dot(u);
        let e=dir1.dot(u);
        let det=a*c-b*b;
        let sNum,tNum,tDenom,sDenom;
        if(det<EPSILON){
            sNum=0;
            tNum=e;
            tDenom=c;
            sDenom=a;
        }else{
            sNum=b*e-c*d;
            tNum=a*e-b*d;
            tDenom=det;
            sDenom=det;
        }
        if(sNum<0){
            sNum=0;
            tNum=e;
            tDenom=c;
        }else if(sNum>det){
            sNum=det;
            tNum=e+b;
            tDenom=c;
        }
        if(tNum<0){
            tNum=0;
            if(-d<0){
                sNum=0;
            }else if(-d>a){
                sNum=sDenom;
            }else{
                sNum=-d;
                sDenom=a;
            }
        }else if(tNum>tDenom){
            tNum=tDenom;
            if((-d+b)<0){
                sNum=0;
            }else if((-d+b)>a){
                sNum=sDenom;
            }else{
                sNum=-d+b;
                sDenom=a;
            }
        }
        let s=sNum/sDenom;
        let t=tNum/tDenom;
        pointOnA.copy(base0).add(dir0.multiplyScalar(s));
        pointOnB.copy(base1).add(dir1.multiplyScalar(t));
        return pointOnA.distanceToSquared(pointOnB);
    },
    /**
     * 轴对齐线到包围盒距离（平方）
     * @param alignedAxis
     * @param origin
     * @param dir
     * @param vExt
     * @param pointerT
     * @returns {number}
     */
    axisAlignedLineDistanceToAabb:(alignedAxis,origin,dir,vExt,pointerT)=>{
        let distanceSquared=0;
        let fiExt,seExt,thExt,fiOri,seOri,thOri,fiDir;
        switch (alignedAxis){
            case 'x':
                fiExt=vExt.x;
                seExt=vExt.y;
                thExt=vExt.z;
                fiOri=origin.x;
                seOri=origin.y;
                thOri=origin.z;
                fiDir=dir.x;
                break;
            case 'y':
                fiExt=vExt.y;
                seExt=vExt.z;
                thExt=vExt.x;
                fiOri=origin.y;
                seOri=origin.z;
                thOri=origin.x;
                fiDir=dir.y;
                break;
            case 'z':
                fiExt=vExt.z;
                seExt=vExt.x;
                thExt=vExt.y;
                fiOri=origin.z;
                seOri=origin.x;
                thOri=origin.y;
                fiDir=dir.z;
                break;
        }

        pointerT.value=(fiExt-fiOri)/fiDir;
        let delta;
        if(seOri<-seExt){
            delta=seOri+seExt;
            distanceSquared+=delta*delta;
        }else if(seOri>seExt){
            delta=seOri-seExt;
            distanceSquared+=delta*delta;
        }
        if(thOri<-thExt){
            delta=thOri+thExt;
            distanceSquared+=delta*delta;
        }else if(thOri>thExt){
            delta=thOri-thExt;
            distanceSquared+=delta*delta;
        }
        return distanceSquared;
    },
    /**
     * 面对齐线到包围盒距离（平方）
     * @param alignedNormal
     * @param origin
     * @param dir
     * @param vExt
     * @param pointerT
     * @returns {number}
     */
    faceAlignedLineDistanceToAabb:(alignedNormal,origin,dir,vExt,pointerT)=>{
        let ptMinusExtents=_v.vec0.subVectors(origin,vExt);

        let fiExt,seExt,thExt,fiOri,seOri,thOri,fiDir,seDir,fiPmt,sePmt;
        switch (alignedNormal){
            case 'xy':
                fiExt=vExt.x;
                seExt=vExt.y;
                thExt=vExt.z;
                fiOri=origin.x;
                seOri=origin.y;
                thOri=origin.z;
                fiDir=dir.x;
                seDir=dir.y;
                fiPmt=ptMinusExtents.x;
                sePmt=ptMinusExtents.y;
                break;
            case 'yz':
                fiExt=vExt.y;
                seExt=vExt.z;
                thExt=vExt.x;
                fiOri=origin.y;
                seOri=origin.z;
                thOri=origin.x;
                fiDir=dir.y;
                seDir=dir.z;
                fiPmt=ptMinusExtents.y;
                sePmt=ptMinusExtents.z;
                break;
            case 'xz':
                fiExt=vExt.z;
                seExt=vExt.x;
                thExt=vExt.y;
                fiOri=origin.z;
                seOri=origin.x;
                thOri=origin.y;
                fiDir=dir.z;
                seDir=dir.x;
                fiPmt=ptMinusExtents.z;
                sePmt=ptMinusExtents.x;
                break;
        }

        let prod0=seDir*fiPmt;
        let prod1=fiDir*sePmt;
        let distanceSquared=0;
        if(prod0>=prod1){
            let tmp=seOri+seExt;
            let delta=prod0-fiDir*tmp;
            if(delta>=0){
                let invLSquared=1/(fiDir*fiDir+seDir*seDir);
                distanceSquared+=(delta*delta)*invLSquared;
                pointerT.value=-(fiDir*fiPmt*seDir+tmp)*invLSquared;
            }else{
                let inv=1/fiDir;
                pointerT.value=-fiPmt*inv;
            }
        }else{
            let tmp=fiOri+fiExt;
            let delta=prod0-seDir*tmp;
            if(delta>=0){
                let invLSquared=1/(fiDir*fiDir+seDir*seDir);
                distanceSquared+=(delta*delta)*invLSquared;
                pointerT.value=-(fiDir*sePmt*seDir+tmp)*invLSquared;
            }else{
                let inv=1/seDir;
                pointerT.value=-sePmt*inv;
            }
        }
        if(thOri<-thExt){
            let delta=thOri+thExt;
            distanceSquared+=delta*delta;
        }else if(thOri>thExt){
            let delta=thOri-thExt;
            distanceSquared+=delta*delta;
        }
        return distanceSquared;
    },
    /**
     * 线段到包围盒面的距离（平方）
     * @param dirFace
     * @param origin
     * @param dir
     * @param vExt
     * @param ptMinusExtents
     * @param t
     * @returns {number}
     */
    segDistanceToAabbFace:(dirFace,origin,dir,vExt,ptMinusExtents,t)=>{
        let distanceSquared=0;
        let ptPlusExtents=_v.vec0.addVectors(origin,vExt);

        let fiOri,seOri,thOri;
        let fiDir,seDir,thDir,fiExt,seExt,thExt,fiPme,sePme,thPme,fiPpe,sePpe,thPpe;
        switch (dirFace){
            case 'x':
                fiDir=dir.x;
                seDir=dir.y;
                thDir=dir.z;
                fiOri=origin.x;
                seOri=origin.y;
                thOri=origin.z;
                fiExt=vExt.x;
                seExt=vExt.y;
                thExt=vExt.z;
                fiPme=ptMinusExtents.x;
                sePme=ptMinusExtents.y;
                thPme=ptMinusExtents.z;
                fiPpe=ptPlusExtents.x;
                sePpe=ptPlusExtents.y;
                thPpe=ptPlusExtents.z;
                break;
            case 'y':
                fiDir=dir.y;
                seDir=dir.z;
                thDir=dir.x;
                fiOri=origin.y;
                seOri=origin.z;
                thOri=origin.x;
                fiExt=vExt.y;
                seExt=vExt.z;
                thExt=vExt.x;
                fiPme=ptMinusExtents.y;
                sePme=ptMinusExtents.z;
                thPme=ptMinusExtents.x;
                fiPpe=ptPlusExtents.y;
                sePpe=ptPlusExtents.z;
                thPpe=ptPlusExtents.x;
                break;
            case 'z':
                fiDir=dir.z;
                seDir=dir.x;
                thDir=dir.y;
                fiOri=origin.z;
                seOri=origin.x;
                thOri=origin.y;
                fiExt=vExt.z;
                seExt=vExt.x;
                thExt=vExt.y;
                fiPme=ptMinusExtents.z;
                sePme=ptMinusExtents.x;
                thPme=ptMinusExtents.y;
                fiPpe=ptPlusExtents.z;
                sePpe=ptPlusExtents.x;
                thPpe=ptPlusExtents.y;
                break;
        }

        let pStep=0;
        if(fiDir*sePpe>=seDir*fiPme){
            if(fiDir*thPpe>=thDir*fiPme){
                let inverse=1/fiDir;
                t.value=-fiPme*inverse;
            }else{
                let lSqr=fiDir*fiDir+thDir*thDir;
                let tmp=lSqr*sePpe-seDir*(fiDir*fiPme+thDir*thPpe);
                if(tmp<=2*lSqr*seExt){
                    tmp=sePpe-(tmp/lSqr);
                    lSqr+=seDir*seDir;
                    let delta=fiDir*fiPme+seDir*tmp+thDir*thPpe;
                    t.value=-delta/lSqr;
                    distanceSquared+=fiPme*fiPme+tmp*tmp+thPpe*thPpe+delta*t.value;
                }else{
                    lSqr+=seDir*seDir;
                    let delta=fiDir*fiPme+seDir*sePme+thDir*thPpe;
                    t.value=-delta/lSqr;
                    distanceSquared+=fiPme*fiPme+sePme*sePme+thPpe*thPpe+delta*t.value;
                }
            }
        }else{
            if(fiDir*thPpe>=thDir*fiPme){
                let lSqr=fiDir*fiDir+seDir*seDir;
                let tmp=lSqr*thPpe-thDir*(fiDir*fiPme+seDir*sePpe);
                if(tmp<=2*lSqr*thExt){
                    tmp=thPpe-(tmp/lSqr);
                    lSqr+=thDir*thDir;
                    let delta=fiDir*fiPme+seDir*sePpe+thDir*tmp;
                    t.value=-delta/lSqr;
                    distanceSquared+=fiPme*fiPme+sePpe*sePpe+tmp*tmp+delta*t.value;
                }else{
                    lSqr+=thDir*thDir;
                    let delta=fiDir*fiPme+seDir*sePpe+thDir*thPme;
                    t.value=-delta/lSqr;
                    distanceSquared+=fiPme*fiPme+sePpe*sePpe+thPme*thPme+delta*t.value;
                }
            }else{
                let lSqr=fiDir*fiDir+thDir*thDir;
                let tmp=lSqr*sePpe-seDir*(fiDir*fiPme+thDir*thPpe);
                if(tmp>=0){
                    if(tmp<=2*lSqr*seExt){
                        tmp=sePpe-(tmp/lSqr);
                        lSqr+=seDir*seDir;
                        let delta=fiDir*fiPme+seDir*tmp+thDir*thPpe;
                        t.value=-delta/lSqr;
                        distanceSquared+=fiPme*fiPme+tmp*tmp+thPpe*thPpe+delta*t.value;
                        pStep=6;
                    }else{
                        lSqr+=seDir*seDir;
                        let delta=fiDir*fiPme+seDir*sePme+thDir*thPpe;
                        t.value=-delta/lSqr;
                        distanceSquared+=fiPme*fiPme+sePme*sePme+thPpe*thPpe+delta*t.value;
                    }
                }
                lSqr=fiDir*fiDir+seDir*seDir;
                tmp=lSqr*thPpe-thDir*(fiDir*fiPme+seDir*sePpe);
                if(tmp>=0){
                    if(tmp<=2*lSqr*thExt){
                        tmp=thPpe-(tmp/lSqr);
                        lSqr+=thDir*thDir;
                        let delta=fiDir*fiPme+seDir*sePpe+thDir*tmp;
                        t.value=-delta/lSqr;
                        distanceSquared+=fiPme*fiPme+sePpe*sePpe+tmp*tmp+delta*t.value;
                    }else{
                        lSqr+=thDir*thDir;
                        let delta=fiDir*fiPme+seDir*sePpe+thDir*thPme;
                        t.value=-delta/lSqr;
                        distanceSquared+=fiPme*fiPme+sePpe*sePpe+thPme*thPme+delta*t.value;
                    }
                }else {
                    if(pStep!==6) {
                        lSqr += thDir * thDir;
                        let delta = fiDir * fiPme + seDir * sePpe + thDir * thPpe;
                        t.value = -delta / lSqr;
                        distanceSquared = fiPme * fiPme + sePpe * sePpe + thPpe * thPpe + delta * t.value;
                    }
                }
            }
        }
        return distanceSquared;
    },
    /**
     * 线到包围盒距离（平方）
     * @param start
     * @param end
     * @param extents
     * @param t
     * @returns {*|number}
     */
    lineDistanceToAabb:(start,end,extents,t)=>{
        let dir=_v.vec01.subVectors(end,start);
        let origin=_v.vec02.copy(start);
        let distanceSquared=0;
        let vExt=_v.vec04.set(...extents);

        if(dir.x<0){
            dir.x*=-1;
            origin.x*=-1;
        }
        if(dir.y<0){
            dir.y*=-1;
            origin.y*=-1;
        }
        if(dir.z<0){
            dir.z*=-1;
            origin.z*=-1;
        }

        if(PrimitiveCompute.isEqual(dir.x,0)&&PrimitiveCompute.isEqual(dir.y,0)&&PrimitiveCompute.isEqual(dir.z,0)){
            distanceSquared=PrimitiveCompute.pointDistanceToAabb(start,extents);
            return distanceSquared;
        }

        if(PrimitiveCompute.isEqual(dir.x,0)&&PrimitiveCompute.isEqual(dir.y,0)){
            distanceSquared=PrimitiveCompute.axisAlignedLineDistanceToAabb('z',origin,dir,vExt,t);
            return distanceSquared;
        }else if(PrimitiveCompute.isEqual(dir.y,0)&&PrimitiveCompute.isEqual(dir.z,0)){
            distanceSquared=PrimitiveCompute.axisAlignedLineDistanceToAabb('x',origin,dir,vExt,t);
            return distanceSquared;
        }else if(PrimitiveCompute.isEqual(dir.x,0)&&PrimitiveCompute.isEqual(dir.z,0)){
            distanceSquared=PrimitiveCompute.axisAlignedLineDistanceToAabb('y',origin,dir,vExt,t);
            return distanceSquared;
        }else if(PrimitiveCompute.isEqual(dir.x,0)){
            distanceSquared=PrimitiveCompute.faceAlignedLineDistanceToAabb('yz',origin,dir,vExt,t);
            return distanceSquared;
        }else if(PrimitiveCompute.isEqual(dir.y,0)){
            distanceSquared=PrimitiveCompute.faceAlignedLineDistanceToAabb('xz',origin,dir,vExt,t);
            return distanceSquared;
        }else if(PrimitiveCompute.isEqual(dir.z,0)){
            distanceSquared=PrimitiveCompute.faceAlignedLineDistanceToAabb('xy',origin,dir,vExt,t);
            return distanceSquared;
        }else{
            let ptMinusExtents=_v.vec03.subVectors(origin,vExt);
            let dyEx=dir.y*ptMinusExtents.x;
            let dxEy=dir.x*ptMinusExtents.y;
            if(dyEx>=dxEy){
                let dzEx=dir.z*ptMinusExtents.x;
                let dxEz=dir.x*ptMinusExtents.z;
                if(dzEx>=dxEz){
                    distanceSquared=PrimitiveCompute.segDistanceToAabbFace('x',origin,dir,vExt,ptMinusExtents,t);
                }else{
                    distanceSquared=PrimitiveCompute.segDistanceToAabbFace('z',origin,dir,vExt,ptMinusExtents,t);
                }
            }else{
                let dzEy=dir.z*ptMinusExtents.y;
                let dyEz=dir.y*ptMinusExtents.z;
                if(dzEy>=dyEz){
                    distanceSquared=PrimitiveCompute.segDistanceToAabbFace('y',origin,dir,vExt,ptMinusExtents,t);
                }else{
                    distanceSquared=PrimitiveCompute.segDistanceToAabbFace('z',origin,dir,vExt,ptMinusExtents,t);
                }
            }
        }
        return distanceSquared;
    },
    /**
     * 线段到包围盒距离（平方）
     * @param start
     * @param end
     * @param extents
     * @returns {*}
     */
    segDistanceToAabb:(start,end,extents)=>{
        let t={value:0};
        let distanceSquared=PrimitiveCompute.lineDistanceToAabb(start,end,extents,t);
        if(t.value<0){
            distanceSquared=PrimitiveCompute.pointDistanceToAabb(start,extents);
        }else if(t.value>1){
            distanceSquared=PrimitiveCompute.pointDistanceToAabb(end,extents);
        }
        return distanceSquared;
    },
    /**
     * 有向有界箱是否相交
     * @param extents0
     * @param transform0
     * @param extents1
     * @param transform1
     * @returns {boolean}
     */
    obbIntersectsObb:(extents0,transform0,extents1,transform1)=>{
        let center0=_v.vec0.set(0,0,0).applyMatrix4(transform0);
        let center1=_v.vec1.set(0,0,0).applyMatrix4(transform1);
        let v = _v.vec0.subVectors(center1 ,center0);

        _v.mat0.extractRotation(transform0);
        let VAx = _v.vec2.set(1, 0, 0).applyMatrix4(_v.mat0);
        let VAy = _v.vec3.set(0, 1, 0).applyMatrix4(_v.mat0);
        let VAz = _v.vec4.set(0, 0, 1).applyMatrix4(_v.mat0);
        let VA = [];
        VA[0] = VAx;
        VA[1] = VAy;
        VA[2] = VAz;

        _v.mat0.extractRotation(transform1);
        let VBx = _v.vec5.set(1, 0, 0).applyMatrix4(_v.mat0);
        let VBy = _v.vec6.set(0, 1, 0).applyMatrix4(_v.mat0);
        let VBz = _v.vec7.set(0, 0, 1).applyMatrix4(_v.mat0);
        let VB =[];
        VB[0] = VBx;
        VB[1] = VBy;
        VB[2] = VBz;
        let T = [v.dot(VAx),v.dot(VAy),v.dot(VAz)];
        let R = [[],[],[]];
        let FR = [[],[],[]];
        let ra, rb, t;
        for (let i = 0; i < 3; i++) {
            for (let k = 0; k < 3; k++) {
                R[i][k] =VA[i].dot(VB[k]);
                FR[i][k] = 1e-6 + Math.abs(R[i][ k]);
            }
        }

        //A基准
        for (let i = 0; i < 3; i++) {
            ra = extents0[i];
            rb = extents1[0] * FR[i][0] + extents1[1] * FR[i][1] + extents1[2] * FR[i][2];
            t = Math.abs(T[i]);
            if (t > ra+rb) return false;
        }

        //B基准
        for (let k = 0; k < 3; k++) {
            ra = extents0[0] * FR[0][k] + extents0[1] * FR[1][k] + extents0[2] * FR[2][k];
            rb = extents1[k];
            t = Math.abs(T[0] * R[0][k] + T[1] * R[1][k] + T[2] * R[2][k]);
            if (t > ra+rb) return false;
        }

        //A0×B0
        ra = extents0[1] * FR[2][0] + extents0[2] * FR[1][0];
        rb = extents1[1] * FR[0][2] + extents1[2] * FR[0][1];
        t = Math.abs(T[2] * R[1][0] - T[1] * R[2][0]);
        if (t > ra+rb) return false;

        //A0×B1
        ra = extents0[1] * FR[2][1] + extents0[2] * FR[1][1];
        rb = extents1[0] * FR[0][2] + extents1[2] * FR[0][0];
        t = Math.abs(T[2] * R[1][1] - T[1] * R[2][1]);
        if (t > ra+rb) return false;

        //A0×B2
        ra = extents0[1] * FR[2][2] + extents0[2] * FR[1][2];
        rb = extents1[0] * FR[0][1] + extents1[1] * FR[0][0];
        t = Math.abs(T[2] * R[1][2] - T[1] * R[2][2]);
        if (t > ra+rb) return false;

        //A1×B0
        ra = extents0[0] * FR[2][0] + extents0[2] * FR[0][0];
        rb = extents1[1] * FR[1][2] + extents1[2] * FR[1][1];
        t = Math.abs(T[0] * R[2][0] - T[2] * R[0][0]);
        if (t > ra+rb) return false;

        //A1×B1
        ra = extents0[0] * FR[2][1] + extents0[2] * FR[0][1];
        rb = extents1[0] * FR[1][2] + extents1[2] * FR[1][0];
        t = Math.abs(T[0] * R[2][1] - T[2] * R[0][1]);
        if (t > ra+rb) return false;

        //A1×B2
        ra = extents0[0] * FR[2][2] + extents0[2] * FR[0][2];
        rb = extents1[0] * FR[1][1] + extents1[1] * FR[1][0];
        t = Math.abs(T[0] * R[2][2] - T[2] * R[0][2]);
        if (t > ra+rb) return false;

        //A2×B0
        ra = extents0[0] * FR[1][0] + extents0[1] * FR[0][0];
        rb = extents1[1] * FR[2][2] + extents1[2] * FR[2][1];
        t = Math.abs(T[1] * R[0][0] - T[0] * R[1][0]);
        if (t > ra+rb) return false;

        //A2×B1
        ra = extents0[0] * FR[1][1] + extents0[1] * FR[0][1];
        rb = extents1[0] * FR[2][2] + extents1[2] * FR[2][0];
        t = Math.abs(T[1] * R[0][1] - T[0] * R[1][1]);
        if (t > ra+rb) return false;

        //A2×B2
        ra = extents0[0] * FR[1][2] + extents0[1] * FR[0][2];
        rb = extents1[0] * FR[2][1] + extents1[1] * FR[2][0];
        t = Math.abs(T[1] * R[0][2] - T[0] * R[1][2]);
        return t<=ra+rb;
    },
    /**
     * 2D凸包是否相交（单向）
     * @param convex0
     * @param convex1
     */
    convex2DIntersectsToConvex2D:(convex0,convex1)=>{
        for(let i=0;i<convex0.length;i++){
            let si=i;
            let ei=i===convex0.length-1?0:i+1;
            let sv=convex0[si];
            let ev=convex0[ei];
            let dirL=_v.vec0;
            dirL.subVectors(ev,sv);
            let dir=_v.vec00;
            dir.crossVectors(AXIS_Z,dirL).normalize();
            let maxDot=0;
            let minDot=0;
            for(let j=0;j<convex0.length;j++){
                if(j===si||j===ei)continue;
                let v=convex0[j];
                let dt=_v.vec1;
                dt.subVectors(v,sv);
                let dot=dt.dot(dir);
                if(maxDot<dot)maxDot=dot;
                if(minDot>dot)minDot=dot;
            }

            let inRange=false;
            let fstDot=null;
            for(let k=0;k<convex1.length;k++){
                let v=convex1[k];
                let dt=_v.vec2;
                dt.subVectors(v,sv);
                let dot=dt.dot(dir);
                if((dot>minDot&&dot<maxDot)||dot===minDot||dot===maxDot){
                    inRange=true;
                    break;
                }else{
                    if(fstDot===null){
                        fstDot=dot;
                    }else{
                        if(fstDot>maxDot){
                            if(dot<minDot){
                                inRange=true;
                                break;
                            }
                        }else if(fstDot<minDot){
                            if(dot>maxDot){
                                inRange=true;
                                break;
                            }
                        }
                    }
                }
            }
            if(!inRange){
                return false;
            }
        }
        return true;
    },
    /**
     * 三维凸壳与三维凸壳的相交检测（固定方向检测）
     * @param vertices0
     * @param vertices1
     * @param pointOnA
     * @param pointOnB
     * @returns {boolean}
     */
    convexIntersectsConvexSeparationAxisFixed:(vertices0,vertices1,pointOnA,pointOnB)=>{
        let info=new Float32Array(9);
        let intersect= SeparationAxisFixed.convexIntersectsConvex(vertices0,vertices1,info);
        pointOnA.set(info[0],info[1],info[2]);
        pointOnB.set(info[3],info[4],info[5]);
        return intersect;
    },
    /**
     *三维凸壳（点集）与球的相交检测（固定方向检测）
     * @param vertices
     * @param sphere {array} [centerX,centerY,centerZ,radius]
     * @param pointOnA
     * @param pointOnB
     * @returns {boolean}
     */
    convexIntersectsSphere:(vertices,sphere,pointOnA,pointOnB)=>{
        let info=new Float32Array(9);
        let intersect=SeparationAxisFixed.convexIntersectsSphere(vertices,sphere,info);
        pointOnA.set(info[0],info[1],info[2]);
        pointOnB.set(info[3],info[4],info[5]);
        return intersect;
    },
    /**
     * 三维凸壳（点集）与胶囊体的相交检测（固定方向检测）
     * @param vertices
     * @param capsule {array} [topCenterX,topCenterY,topCenterZ,bottomCenterX,bottomCenterY,bottomCenterZ,radius]
     * @param pointOnA
     * @param pointOnB
     */
    convexIntersectsCapsule:(vertices,capsule,pointOnA,pointOnB)=>{
        let info=new Float32Array(9);
        let intersect=SeparationAxisFixed.convexIntersectsCapsule(vertices,capsule,info);
        pointOnA.set(info[0],info[1],info[2]);
        pointOnB.set(info[3],info[4],info[5]);
        return intersect;
    },
};

export default PrimitiveCompute;